In this document, we analyse missing data patterns in the dataset.
First of all, we noticed that there are some issues with the dataset and therefore, for now, restrict the dataset to get rid off these issues. In particular, we do not have any pollution data for 2014 nor for NO in 2015 and very few observations for PMs in 2019. These issue do not come from actual missing data but are due to issue with the package we used to access the pollution data. These data are available through the EEA interface.
data <- data_imputation %>%
mutate(year = lubridate::year(date)) %>%
filter(year != 2014) %>%
filter(!(year == 2015 & pollutant == "no")) %>%
filter(!(year == 2019 & str_sub(pollutant, 1, 2) == "pm")) %>%
select(-year)
# rm(data_imputation)
Location of measurement stations
The stations considered are located in the 17 biggest largest in France:
| Bordeaux |
4 |
| Clermont-Ferrand |
13 |
| Dijon |
7 |
| Grenoble |
5 |
| Le Havre |
17 |
| Lille |
7 |
| Lyon |
22 |
| Marseille |
11 |
| Montpellier |
7 |
| Nancy |
4 |
| Nantes |
16 |
| Nice |
9 |
| Paris |
29 |
| Rennes |
9 |
| Rouen |
7 |
| Strasbourg |
9 |
| Toulouse |
19 |
Missing data patterns in the sample
Here, we investigate whether missing pollutant concentration data varies across different dimentions.
The overall share of missing values is 0.046308.
#' Graphs describing the proportion of missing values in different groups
#'
#' Enables to plot the proportion of missing values by a number of
#'
#' @param df A dataframe. Dataframe to analyse
#' @param grouping_var A string. Name of the variable, in \code{df}, for which the proportion of missing values needs to be displayed
#' @param bins An integer. Number of bins to slice \code{grouping_var} in, if it is a continuous value.
#' @param facet_var A string. Name of the variable, in \code{df}, by which to facet the initial graph
#' @param y_axis_to An integer. Limit of the y axis
#' @export
#'
hist_missing_by <- function(df, variable_missing = "concentration", grouping_var, bins = 10, facet_var = NA, y_axis_to = 1) {
grouping_var_name <- str_replace_all(grouping_var, pattern = "_", replacement = " ")
variable_missing_name <- str_replace_all(variable_missing, pattern = "_", replacement = " ")
if (!is.factor(df[[grouping_var]]) && !is.na(as.numeric(df[[grouping_var]]))) {
df[[grouping_var]] <- cut_interval(as.numeric(df[[grouping_var]]), bins)
}
graph <- df %>%
filter(!is.na(.data[[grouping_var]])) %>%
group_by_(grouping_var, facet_var) %>%
summarise(share_missing = sum(is.na(.data[[variable_missing]]))/n()) %>%
arrange(share_missing) %>%
ggplot() +
# geom_point(aes(x = .data[[grouping_var]], y = share_missing)) +
# geom_line(aes(x = .data[[grouping_var]], y = share_missing)) +
geom_col(aes(x = .data[[grouping_var]], y = share_missing)) +
labs(
title = paste("Share of missing", variable_missing_name,"data by", grouping_var_name),
x = str_to_sentence(grouping_var_name),
y = paste("Share of missing", variable_missing_name,"data")
)
if (!is.null(y_axis_to)) {
graph <- graph +
ylim(0, y_axis_to)
}
if (!is.na(facet_var)) {
graph <- graph +
facet_wrap(facets = facet_var)
}
return(graph)
}
Across pollutants
We can break this down by pollutant.

One can notice that the share of missing values varies across pollutants, up to about a factor two. This higlights the potential necessity of analysing missingness patterns independently across pollutants.
Across locations
We look weather missingness patterns vary across cities.
data %>%
hist_missing_by(grouping_var = "city") +
coord_flip()

data %>%
hist_missing_by(grouping_var = "site_area")

data %>%
hist_missing_by(grouping_var = "site_type")

data %>%
hist_missing_by(grouping_var = "elevation")

data %>%
hist_missing_by(grouping_var = "latitude")

Across dates and time
Overall, we notice that, along the time dimension data almost seems to be missing at random appart from a decreasing trend in the proportion of missing data
data %>%
mutate(year = year(date)) %>%
hist_missing_by(grouping_var = "year")

We look at whether this variation comes more from some pollutants than others.
data %>%
mutate(year = year(date)) %>%
group_by(pollutant, year) %>%
summarise(share_missing = sum(is.na(concentration))/n()) %>%
arrange(share_missing) %>%
ggplot() +
geom_col(aes(x = factor(year), y = share_missing, fill = pollutant), position = "dodge") +
labs(title = "Share of missing PM10 concentration data by year and pollutant", x = "Year", y = "Share of missing PM10 concentration data") +
ylim(0, 1)

Zooming in and looking at monthly data, we can see that this decreasing trend is somehow step wise, with some important decreases between December and January.
data %>%
mutate(year_month = paste(year(date), str_pad(month(date), 2, pad = 0))) %>%
hist_missing_by(grouping_var = "year_month")

We now investigate whether the share of missing data varies across month of the year, day of the month and day of the week. There does not seem to be huge variations.
Month
data %>%
mutate(month = factor(month(date))) %>%
hist_missing_by(grouping_var = "month")

data %>%
mutate(
year = factor(year(date)),
month = factor(month(date))
) %>%
hist_missing_by(grouping_var = "month", facet_var = "year")

Day of the month
data %>%
mutate(day_of_month = factor(day(date))) %>%
hist_missing_by(grouping_var = "day_of_month")

data %>%
mutate(
year = factor(year(date)),
day_of_month = factor(day(date))
) %>%
hist_missing_by(grouping_var = "day_of_month", facet_var = "year")

data %>%
mutate(
month = factor(month(date)),
day_of_month = factor(day(date))
) %>%
hist_missing_by(grouping_var = "day_of_month", facet_var = "month")

Day of the week
data %>%
mutate(day_in_week = factor(wday(date))) %>%
hist_missing_by(grouping_var = "day_in_week")

data %>%
mutate(
year = factor(year(date)),
day_in_week = factor(wday(date))
) %>%
hist_missing_by(grouping_var = "day_in_week", facet_var = "year")

data %>%
mutate(
month = factor(month(date)),
day_in_week = factor(wday(date))
) %>%
hist_missing_by(grouping_var = "day_in_week", facet_var = "month")

Hour of the day
Now we investigate whether there are some variation in missingness patterns across time.
data %>%
mutate(hour = factor(hour(date))) %>%
hist_missing_by(grouping_var = "hour")

data %>%
mutate(hour = factor(hour(date))) %>%
hist_missing_by(grouping_var = "hour", facet_var = "pollutant")

Across weather patterns
Temperature
data %>%
hist_missing_by(grouping_var = "temperature")

Wind
data %>%
hist_missing_by(grouping_var = "wind_speed")

data %>%
hist_missing_by(grouping_var = "wind_speed_max")

data %>%
hist_missing_by(grouping_var = "wind_direction", y_axis_to = 0.1) +
coord_polar()

data %>%
hist_missing_by(grouping_var = "wind_direction_max", y_axis_to = 0.1) +
coord_polar()

Rainfall
data %>%
hist_missing_by(grouping_var = "rainfall_height")

data %>%
hist_missing_by(grouping_var = "rainfall_duration")

Other weather variables
data %>%
hist_missing_by(grouping_var = "relative_humidity")

data %>%
hist_missing_by(grouping_var = "sea_level_pressure")

data %>%
hist_missing_by(grouping_var = "insolation_duration")

data %>%
hist_missing_by(grouping_var = "global_radiation")

data %>%
hist_missing_by(grouping_var = "uv_radiation")

LS0tCnRpdGxlOiAiQW5hbHlzaXMgb2YgbWlzc2luZyBkYXRhIHBhdHRlcm5zIgphdXRob3I6CiAgLSBuYW1lOiBWaW5jZW50IEJhZ2lsZXQgCiAgICB1cmw6IGh0dHBzOi8vd3d3LnNpcGEuY29sdW1iaWEuZWR1L2V4cGVyaWVuY2Utc2lwYS9zaXBhLXByb2ZpbGVzL3ZpbmNlbnQtYmFnaWxldAogICAgYWZmaWxpYXRpb246IENvbHVtYmlhIFVuaXZlcnNpdHkKICAgIGFmZmlsaWF0aW9uX3VybDogaHR0cHM6Ly93d3cuY29sdW1iaWEuZWR1LwogIC0gbmFtZTogTMOpbyBaYWJyb2NraSAKICAgIHVybDogaHR0cHM6Ly93d3cucGFyaXNzY2hvb2xvZmVjb25vbWljcy5ldS9lbi8KICAgIGFmZmlsaWF0aW9uOiBQYXJpcyBTY2hvb2wgb2YgRWNvbm9taWNzCiAgICBhZmZpbGlhdGlvbl91cmw6IGh0dHBzOi8vd3d3LnBhcmlzc2Nob29sb2ZlY29ub21pY3MuZXUvZW4vCmRhdGU6ICJgciBTeXMuRGF0ZSgpYCIKb3V0cHV0OiBkaXN0aWxsOjpkaXN0aWxsX2FydGljbGUKLS0tCgo8c3R5bGU+CmJvZHkgewp0ZXh0LWFsaWduOiBqdXN0aWZ5fQo8L3N0eWxlPgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0UsIHJlc3VsdHM9J2hpZGUnLCB3YXJuaW5nPUZBTFNFfQpsaWJyYXJ5KGtuaXRyKQpvcHRzX2NodW5rJHNldChmaWcucGF0aCA9ICJpbWFnZXMvIiwKICAgICAgICAgICAgICAgY2FjaGUucGF0aCA9ICJjYWNoZS8iLAogICAgICAgICAgICAgICBjYWNoZSA9IEZBTFNFLAogICAgICAgICAgICAgICBlY2hvID0gVFJVRSwKICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLAogICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UpICAKYGBgICAKCmBgYHtyIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KG1lZGlvY3JldGhlbWVzKQpsaWJyYXJ5KG1hcHMpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KGxlYWZsZXQpCgpzZXRfbWVkaW9jcmVfYWxsKCkKYGBgCgpgYGB7ciBpbmNsdWRlPUZBTFNFfQptZXRhZGF0YV9wb2xsdXRpb24gPC0gcmVhZFJEUygiLi4vT3V0cHV0cy9jbGVhbl9tZXRhZGF0YV9wb2xsdXRpb24uUkRTIikKZGF0YV9pbXB1dGF0aW9uIDwtIHJlYWRSRFMoIi4uL091dHB1dHMvZGF0YV9pbXB1dGF0aW9uLlJEUyIpCiMgcmF3IDwtIHJlYWRSRFMoIi4uL091dHB1dHMvcmF3X2Fpcl9wb2xsdXRpb25fZGF0YS5SRFMiKQpgYGAKCkluIHRoaXMgZG9jdW1lbnQsIHdlIGFuYWx5c2UgbWlzc2luZyBkYXRhIHBhdHRlcm5zIGluIHRoZSBkYXRhc2V0LiAKCkZpcnN0IG9mIGFsbCwgd2Ugbm90aWNlZCB0aGF0IHRoZXJlIGFyZSBzb21lIGlzc3VlcyB3aXRoIHRoZSBkYXRhc2V0IGFuZCB0aGVyZWZvcmUsIGZvciBub3csIHJlc3RyaWN0IHRoZSBkYXRhc2V0IHRvIGdldCByaWQgb2ZmIHRoZXNlIGlzc3Vlcy4gSW4gcGFydGljdWxhciwgd2UgZG8gbm90IGhhdmUgYW55IHBvbGx1dGlvbiBkYXRhIGZvciAyMDE0IG5vciBmb3IgTk8gaW4gMjAxNSBhbmQgdmVyeSBmZXcgb2JzZXJ2YXRpb25zIGZvciBQTXMgaW4gMjAxOS4gVGhlc2UgaXNzdWUgZG8gbm90IGNvbWUgZnJvbSBhY3R1YWwgbWlzc2luZyBkYXRhIGJ1dCBhcmUgZHVlIHRvIGlzc3VlIHdpdGggdGhlIHBhY2thZ2Ugd2UgdXNlZCB0byBhY2Nlc3MgdGhlIHBvbGx1dGlvbiBkYXRhLiBUaGVzZSBkYXRhIGFyZSBhdmFpbGFibGUgdGhyb3VnaCB0aGUgRUVBIGludGVyZmFjZS4KCmBgYHtyfQpkYXRhIDwtIGRhdGFfaW1wdXRhdGlvbiAlPiUgIAogIG11dGF0ZSh5ZWFyID0gbHVicmlkYXRlOjp5ZWFyKGRhdGUpKSAlPiUgCiAgZmlsdGVyKHllYXIgIT0gMjAxNCkgJT4lIAogIGZpbHRlcighKHllYXIgPT0gMjAxNSAmIHBvbGx1dGFudCA9PSAibm8iKSkgJT4lIAogIGZpbHRlcighKHllYXIgPT0gMjAxOSAmIHN0cl9zdWIocG9sbHV0YW50LCAxLCAyKSA9PSAicG0iKSkgJT4lIAogIHNlbGVjdCgteWVhcikKICAKcm0oZGF0YV9pbXB1dGF0aW9uKQpgYGAKCgojIExvY2F0aW9uIG9mIG1lYXN1cmVtZW50IHN0YXRpb25zCgpUaGUgc3RhdGlvbnMgY29uc2lkZXJlZCBhcmUgbG9jYXRlZCBpbiB0aGUgMTcgYmlnZ2VzdCBsYXJnZXN0IGluIEZyYW5jZToKCmBgYHtyfQptZXRhZGF0YV9wb2xsdXRpb24gJT4lIAogIGNvdW50KGNpdHkpICU+JSAKICBrYWJsZShjb2wubmFtZXMgPSBjKCJDaXR5IiwgIk51bWJlciBvZiBzdGF0aW9ucyIpKQpgYGAKCiMgTWlzc2luZyBkYXRhIHBhdHRlcm5zIGluIHRoZSBzYW1wbGUKCkhlcmUsIHdlIGludmVzdGlnYXRlIHdoZXRoZXIgbWlzc2luZyBwb2xsdXRhbnQgY29uY2VudHJhdGlvbiBkYXRhIHZhcmllcyBhY3Jvc3MgZGlmZmVyZW50IGRpbWVudGlvbnMuIAoKYGBge3IgaW5jbHVkZSA9IEZBTFNFfQpzaGFyZV9taXNzaW5nIDwtIHN1bShpcy5uYShkYXRhJGNvbmNlbnRyYXRpb24pKS9ucm93KGRhdGEpCmBgYAoKVGhlIG92ZXJhbGwgc2hhcmUgb2YgbWlzc2luZyB2YWx1ZXMgaXMgYHIgc2hhcmVfbWlzc2luZ2AuCgpgYGB7cn0KIycgR3JhcGhzIGRlc2NyaWJpbmcgdGhlIHByb3BvcnRpb24gb2YgbWlzc2luZyB2YWx1ZXMgaW4gZGlmZmVyZW50IGdyb3VwcwojJwojJyBFbmFibGVzIHRvIHBsb3QgdGhlIHByb3BvcnRpb24gb2YgbWlzc2luZyB2YWx1ZXMgYnkgYSBudW1iZXIgb2YgCiMnCiMnIEBwYXJhbSBkZiBBIGRhdGFmcmFtZS4gRGF0YWZyYW1lIHRvIGFuYWx5c2UgCiMnIEBwYXJhbSBncm91cGluZ192YXIgQSBzdHJpbmcuIE5hbWUgb2YgdGhlIHZhcmlhYmxlLCBpbiBcY29kZXtkZn0sIGZvciB3aGljaCB0aGUgcHJvcG9ydGlvbiBvZiBtaXNzaW5nIHZhbHVlcyBuZWVkcyB0byBiZSBkaXNwbGF5ZWQKIycgQHBhcmFtIGJpbnMgQW4gaW50ZWdlci4gTnVtYmVyIG9mIGJpbnMgdG8gc2xpY2UgXGNvZGV7Z3JvdXBpbmdfdmFyfSBpbiwgaWYgaXQgaXMgYSBjb250aW51b3VzIHZhbHVlLgojJyBAcGFyYW0gZmFjZXRfdmFyIEEgc3RyaW5nLiBOYW1lIG9mIHRoZSB2YXJpYWJsZSwgaW4gXGNvZGV7ZGZ9LCBieSB3aGljaCB0byBmYWNldCB0aGUgaW5pdGlhbCBncmFwaAojJyBAcGFyYW0geV9heGlzX3RvIEFuIGludGVnZXIuIExpbWl0IG9mIHRoZSB5IGF4aXMKIycgQGV4cG9ydAojJwpoaXN0X21pc3NpbmdfYnkgPC0gZnVuY3Rpb24oZGYsIHZhcmlhYmxlX21pc3NpbmcgPSAiY29uY2VudHJhdGlvbiIsIGdyb3VwaW5nX3ZhciwgYmlucyA9IDEwLCBmYWNldF92YXIgPSBOQSwgeV9heGlzX3RvID0gMSkgewogIAogIGdyb3VwaW5nX3Zhcl9uYW1lIDwtIHN0cl9yZXBsYWNlX2FsbChncm91cGluZ192YXIsIHBhdHRlcm4gPSAiXyIsIHJlcGxhY2VtZW50ID0gIiAiKQogIHZhcmlhYmxlX21pc3NpbmdfbmFtZSA8LSBzdHJfcmVwbGFjZV9hbGwodmFyaWFibGVfbWlzc2luZywgcGF0dGVybiA9ICJfIiwgcmVwbGFjZW1lbnQgPSAiICIpCiAgCiAgaWYgKCFpcy5mYWN0b3IoZGZbW2dyb3VwaW5nX3Zhcl1dKSAmJiAhaXMubmEoYXMubnVtZXJpYyhkZltbZ3JvdXBpbmdfdmFyXV0pKSkgewogICAgZGZbW2dyb3VwaW5nX3Zhcl1dIDwtIGN1dF9pbnRlcnZhbChhcy5udW1lcmljKGRmW1tncm91cGluZ192YXJdXSksIGJpbnMpCiAgfSAKICAKICBncmFwaCA8LSBkZiAlPiUgCiAgICBmaWx0ZXIoIWlzLm5hKC5kYXRhW1tncm91cGluZ192YXJdXSkpICU+JSAKICAgIGdyb3VwX2J5Xyhncm91cGluZ192YXIsIGZhY2V0X3ZhcikgJT4lCiAgICBzdW1tYXJpc2Uoc2hhcmVfbWlzc2luZyA9IHN1bShpcy5uYSguZGF0YVtbdmFyaWFibGVfbWlzc2luZ11dKSkvbigpKSAlPiUKICAgIGFycmFuZ2Uoc2hhcmVfbWlzc2luZykgJT4lCiAgICBnZ3Bsb3QoKSArCiAgICAjIGdlb21fcG9pbnQoYWVzKHggPSAuZGF0YVtbZ3JvdXBpbmdfdmFyXV0sIHkgPSBzaGFyZV9taXNzaW5nKSkgKwogICAgIyBnZW9tX2xpbmUoYWVzKHggPSAuZGF0YVtbZ3JvdXBpbmdfdmFyXV0sIHkgPSBzaGFyZV9taXNzaW5nKSkgKwogICAgZ2VvbV9jb2woYWVzKHggPSAuZGF0YVtbZ3JvdXBpbmdfdmFyXV0sIHkgPSBzaGFyZV9taXNzaW5nKSkgKwogICAgbGFicygKICAgICAgdGl0bGUgPSBwYXN0ZSgiU2hhcmUgb2YgbWlzc2luZyIsIHZhcmlhYmxlX21pc3NpbmdfbmFtZSwiZGF0YSBieSIsIGdyb3VwaW5nX3Zhcl9uYW1lKSwKICAgICAgeCA9IHN0cl90b19zZW50ZW5jZShncm91cGluZ192YXJfbmFtZSksIAogICAgICB5ID0gcGFzdGUoIlNoYXJlIG9mIG1pc3NpbmciLCB2YXJpYWJsZV9taXNzaW5nX25hbWUsImRhdGEiKQogICAgKSAKICAKICBpZiAoIWlzLm51bGwoeV9heGlzX3RvKSkgewogICAgZ3JhcGggPC0gZ3JhcGggKyAKICAgICAgeWxpbSgwLCB5X2F4aXNfdG8pIAogIH0KICAgCiAgaWYgKCFpcy5uYShmYWNldF92YXIpKSB7CiAgICBncmFwaCA8LSBncmFwaCArCiAgICBmYWNldF93cmFwKGZhY2V0cyA9IGZhY2V0X3ZhcikKICB9IAogIAogIHJldHVybihncmFwaCkKfQpgYGAKCgojIyBBY3Jvc3MgcG9sbHV0YW50cwoKV2UgY2FuIGJyZWFrIHRoaXMgZG93biBieSBwb2xsdXRhbnQuCgpgYGB7cn0KZGF0YSAlPiUgIAogIGhpc3RfbWlzc2luZ19ieShncm91cGluZ192YXIgPSAicG9sbHV0YW50IikgCmBgYAoKCk9uZSBjYW4gbm90aWNlIHRoYXQgdGhlIHNoYXJlIG9mIG1pc3NpbmcgdmFsdWVzIHZhcmllcyBhY3Jvc3MgcG9sbHV0YW50cywgdXAgdG8gYWJvdXQgYSBmYWN0b3IgdHdvLiBUaGlzIGhpZ2xpZ2h0cyB0aGUgcG90ZW50aWFsIG5lY2Vzc2l0eSBvZiBhbmFseXNpbmcgbWlzc2luZ25lc3MgcGF0dGVybnMgaW5kZXBlbmRlbnRseSBhY3Jvc3MgcG9sbHV0YW50cy4KCiMjIEFjcm9zcyBsb2NhdGlvbnMKCldlIGxvb2sgd2VhdGhlciBtaXNzaW5nbmVzcyBwYXR0ZXJucyB2YXJ5IGFjcm9zcyBjaXRpZXMuCgpgYGB7cn0KZGF0YSAlPiUgCiAgaGlzdF9taXNzaW5nX2J5KGdyb3VwaW5nX3ZhciA9ICJjaXR5IikgKwogIGNvb3JkX2ZsaXAoKQpgYGAKCmBgYHtyfQpkYXRhICU+JSAgCiAgaGlzdF9taXNzaW5nX2J5KGdyb3VwaW5nX3ZhciA9ICJzaXRlX2FyZWEiKSAKYGBgCgpgYGB7cn0KZGF0YSAlPiUgIAogIGhpc3RfbWlzc2luZ19ieShncm91cGluZ192YXIgPSAic2l0ZV90eXBlIikgCmBgYAoKCmBgYHtyfQpkYXRhICU+JSAKICBoaXN0X21pc3NpbmdfYnkoZ3JvdXBpbmdfdmFyID0gImVsZXZhdGlvbiIpIApgYGAKCmBgYHtyfQpkYXRhICU+JSAKICBoaXN0X21pc3NpbmdfYnkoZ3JvdXBpbmdfdmFyID0gImxhdGl0dWRlIikgCmBgYAoKCiMjIEFjcm9zcyBkYXRlcyBhbmQgdGltZQoKT3ZlcmFsbCwgd2Ugbm90aWNlIHRoYXQsIGFsb25nIHRoZSB0aW1lIGRpbWVuc2lvbiBkYXRhIGFsbW9zdCBzZWVtcyB0byBiZSBtaXNzaW5nIGF0IHJhbmRvbSBhcHBhcnQgZnJvbSBhIGRlY3JlYXNpbmcgdHJlbmQgaW4gdGhlIHByb3BvcnRpb24gb2YgbWlzc2luZyBkYXRhIAoKYGBge3J9CmRhdGEgJT4lICAKICBtdXRhdGUoeWVhciA9IHllYXIoZGF0ZSkpICU+JSAKICBoaXN0X21pc3NpbmdfYnkoZ3JvdXBpbmdfdmFyID0gInllYXIiKSAKYGBgCgpXZSBsb29rIGF0IHdoZXRoZXIgdGhpcyB2YXJpYXRpb24gY29tZXMgbW9yZSBmcm9tIHNvbWUgcG9sbHV0YW50cyB0aGFuIG90aGVycy4KCmBgYHtyfQpkYXRhICU+JSAKICBtdXRhdGUoeWVhciA9IHllYXIoZGF0ZSkpICU+JSAKICBncm91cF9ieShwb2xsdXRhbnQsIHllYXIpICU+JSAKICBzdW1tYXJpc2Uoc2hhcmVfbWlzc2luZyA9IHN1bShpcy5uYShjb25jZW50cmF0aW9uKSkvbigpKSAlPiUgCiAgYXJyYW5nZShzaGFyZV9taXNzaW5nKSAlPiUgCiAgZ2dwbG90KCkgKyAKICBnZW9tX2NvbChhZXMoeCA9IGZhY3Rvcih5ZWFyKSwgeSA9IHNoYXJlX21pc3NpbmcsIGZpbGwgPSBwb2xsdXRhbnQpLCBwb3NpdGlvbiA9ICJkb2RnZSIpICsgCiAgbGFicyh0aXRsZSA9ICJTaGFyZSBvZiBtaXNzaW5nIFBNMTAgY29uY2VudHJhdGlvbiBkYXRhIGJ5IHllYXIgYW5kIHBvbGx1dGFudCIsIHggPSAiWWVhciIsIHkgPSAgIlNoYXJlIG9mIG1pc3NpbmcgUE0xMCBjb25jZW50cmF0aW9uIGRhdGEiKSArCiAgeWxpbSgwLCAxKQpgYGAKClpvb21pbmcgaW4gYW5kIGxvb2tpbmcgYXQgbW9udGhseSBkYXRhLCB3ZSBjYW4gc2VlIHRoYXQgdGhpcyBkZWNyZWFzaW5nIHRyZW5kIGlzIHNvbWVob3cgc3RlcCB3aXNlLCB3aXRoIHNvbWUgaW1wb3J0YW50IGRlY3JlYXNlcyBiZXR3ZWVuIERlY2VtYmVyIGFuZCBKYW51YXJ5LgoKYGBge3J9CmRhdGEgJT4lICAKICBtdXRhdGUoeWVhcl9tb250aCA9IHBhc3RlKHllYXIoZGF0ZSksIHN0cl9wYWQobW9udGgoZGF0ZSksIDIsIHBhZCA9IDApKSkgJT4lIAogIGhpc3RfbWlzc2luZ19ieShncm91cGluZ192YXIgPSAieWVhcl9tb250aCIpIApgYGAKCgpXZSBub3cgaW52ZXN0aWdhdGUgd2hldGhlciB0aGUgc2hhcmUgb2YgbWlzc2luZyBkYXRhIHZhcmllcyBhY3Jvc3MgbW9udGggb2YgdGhlIHllYXIsIGRheSBvZiB0aGUgbW9udGggYW5kIGRheSBvZiB0aGUgd2Vlay4gVGhlcmUgZG9lcyBub3Qgc2VlbSB0byBiZSBodWdlIHZhcmlhdGlvbnMuCgojIyMgTW9udGgKCmBgYHtyfQpkYXRhICU+JQogIG11dGF0ZShtb250aCA9IGZhY3Rvcihtb250aChkYXRlKSkpICU+JSAKICBoaXN0X21pc3NpbmdfYnkoZ3JvdXBpbmdfdmFyID0gIm1vbnRoIikKCmRhdGEgJT4lICAKICBtdXRhdGUoCiAgICB5ZWFyID0gZmFjdG9yKHllYXIoZGF0ZSkpLCAKICAgIG1vbnRoID0gZmFjdG9yKG1vbnRoKGRhdGUpKQogICkgJT4lIAogIGhpc3RfbWlzc2luZ19ieShncm91cGluZ192YXIgPSAibW9udGgiLCBmYWNldF92YXIgPSAieWVhciIpCmBgYAoKIyMjIERheSBvZiB0aGUgbW9udGgKCmBgYHtyfQpkYXRhICU+JQogIG11dGF0ZShkYXlfb2ZfbW9udGggPSBmYWN0b3IoZGF5KGRhdGUpKSkgJT4lIAogIGhpc3RfbWlzc2luZ19ieShncm91cGluZ192YXIgPSAiZGF5X29mX21vbnRoIikKCmRhdGEgJT4lICAKICBtdXRhdGUoCiAgICB5ZWFyID0gZmFjdG9yKHllYXIoZGF0ZSkpLCAKICAgIGRheV9vZl9tb250aCA9IGZhY3RvcihkYXkoZGF0ZSkpCiAgKSAlPiUgCiAgaGlzdF9taXNzaW5nX2J5KGdyb3VwaW5nX3ZhciA9ICJkYXlfb2ZfbW9udGgiLCBmYWNldF92YXIgPSAieWVhciIpCgpkYXRhICU+JSAgCiAgbXV0YXRlKAogICAgbW9udGggPSBmYWN0b3IobW9udGgoZGF0ZSkpLCAKICAgIGRheV9vZl9tb250aCA9IGZhY3RvcihkYXkoZGF0ZSkpCiAgKSAlPiUgCiAgaGlzdF9taXNzaW5nX2J5KGdyb3VwaW5nX3ZhciA9ICJkYXlfb2ZfbW9udGgiLCBmYWNldF92YXIgPSAibW9udGgiKQpgYGAKCiMjIyBEYXkgb2YgdGhlIHdlZWsKCmBgYHtyfQpkYXRhICU+JQogIG11dGF0ZShkYXlfaW5fd2VlayA9IGZhY3Rvcih3ZGF5KGRhdGUpKSkgJT4lIAogIGhpc3RfbWlzc2luZ19ieShncm91cGluZ192YXIgPSAiZGF5X2luX3dlZWsiKQoKZGF0YSAlPiUgIAogIG11dGF0ZSgKICAgIHllYXIgPSBmYWN0b3IoeWVhcihkYXRlKSksIAogICAgZGF5X2luX3dlZWsgPSBmYWN0b3Iod2RheShkYXRlKSkKICApICU+JSAKICBoaXN0X21pc3NpbmdfYnkoZ3JvdXBpbmdfdmFyID0gImRheV9pbl93ZWVrIiwgZmFjZXRfdmFyID0gInllYXIiKQoKZGF0YSAlPiUgIAogIG11dGF0ZSgKICAgIG1vbnRoID0gZmFjdG9yKG1vbnRoKGRhdGUpKSwgCiAgICBkYXlfaW5fd2VlayA9IGZhY3Rvcih3ZGF5KGRhdGUpKQogICkgJT4lIAogIGhpc3RfbWlzc2luZ19ieShncm91cGluZ192YXIgPSAiZGF5X2luX3dlZWsiLCBmYWNldF92YXIgPSAibW9udGgiKQpgYGAKCgojIyMgSG91ciBvZiB0aGUgZGF5CgpOb3cgd2UgaW52ZXN0aWdhdGUgd2hldGhlciB0aGVyZSBhcmUgc29tZSB2YXJpYXRpb24gaW4gbWlzc2luZ25lc3MgcGF0dGVybnMgYWNyb3NzIHRpbWUuCgpgYGB7cn0KZGF0YSAlPiUKICBtdXRhdGUoaG91ciA9IGZhY3Rvcihob3VyKGRhdGUpKSkgJT4lIAogIGhpc3RfbWlzc2luZ19ieShncm91cGluZ192YXIgPSAiaG91ciIpCmBgYAoKCgoKYGBge3J9CmRhdGEgJT4lCiAgbXV0YXRlKGhvdXIgPSBmYWN0b3IoaG91cihkYXRlKSkpICU+JSAKICBoaXN0X21pc3NpbmdfYnkoZ3JvdXBpbmdfdmFyID0gImhvdXIiLCBmYWNldF92YXIgPSAicG9sbHV0YW50IikKYGBgCgoKIyMgQWNyb3NzIHdlYXRoZXIgcGF0dGVybnMKCiMjIyBUZW1wZXJhdHVyZQoKYGBge3J9CmRhdGEgJT4lCiAgaGlzdF9taXNzaW5nX2J5KGdyb3VwaW5nX3ZhciA9ICJ0ZW1wZXJhdHVyZSIpCmBgYAoKIyMjIFdpbmQKCmBgYHtyfQpkYXRhICU+JSAKICBoaXN0X21pc3NpbmdfYnkoZ3JvdXBpbmdfdmFyID0gIndpbmRfc3BlZWQiKQpgYGAKCmBgYHtyfQpkYXRhICU+JSAKICBoaXN0X21pc3NpbmdfYnkoZ3JvdXBpbmdfdmFyID0gIndpbmRfc3BlZWRfbWF4IikKYGBgCgpgYGB7cn0KZGF0YSAlPiUgCiAgaGlzdF9taXNzaW5nX2J5KGdyb3VwaW5nX3ZhciA9ICJ3aW5kX2RpcmVjdGlvbiIsIHlfYXhpc190byA9IDAuMSkgKwogIGNvb3JkX3BvbGFyKCkKYGBgCgoKYGBge3J9CmRhdGEgJT4lIAogIGhpc3RfbWlzc2luZ19ieShncm91cGluZ192YXIgPSAid2luZF9kaXJlY3Rpb25fbWF4IiwgeV9heGlzX3RvID0gMC4xKSArCiAgY29vcmRfcG9sYXIoKQpgYGAKCiMjIyBSYWluZmFsbAoKYGBge3J9CmRhdGEgJT4lIAogIGhpc3RfbWlzc2luZ19ieShncm91cGluZ192YXIgPSAicmFpbmZhbGxfaGVpZ2h0IikgCmBgYAoKCgpgYGB7cn0KZGF0YSAlPiUgCiAgaGlzdF9taXNzaW5nX2J5KGdyb3VwaW5nX3ZhciA9ICJyYWluZmFsbF9kdXJhdGlvbiIpIApgYGAKCiMjIyBPdGhlciB3ZWF0aGVyIHZhcmlhYmxlcwoKYGBge3J9CmRhdGEgJT4lIAogIGhpc3RfbWlzc2luZ19ieShncm91cGluZ192YXIgPSAicmVsYXRpdmVfaHVtaWRpdHkiKSAKYGBgCgoKCmBgYHtyfQpkYXRhICU+JSAKICBoaXN0X21pc3NpbmdfYnkoZ3JvdXBpbmdfdmFyID0gInNlYV9sZXZlbF9wcmVzc3VyZSIpIApgYGAKCgpgYGB7cn0KZGF0YSAlPiUgCiAgaGlzdF9taXNzaW5nX2J5KGdyb3VwaW5nX3ZhciA9ICJpbnNvbGF0aW9uX2R1cmF0aW9uIikgCmBgYAoKCgpgYGB7cn0KZGF0YSAlPiUgCiAgaGlzdF9taXNzaW5nX2J5KGdyb3VwaW5nX3ZhciA9ICJnbG9iYWxfcmFkaWF0aW9uIikgCmBgYAoKCgpgYGB7cn0KZGF0YSAlPiUgCiAgaGlzdF9taXNzaW5nX2J5KGdyb3VwaW5nX3ZhciA9ICJ1dl9yYWRpYXRpb24iKSAKYGBgCgoKCg==